#include "bsp_i2c1.h"
#include "bsp.h"
#if (CONFIG_OS_ENABLE == 1)
#include "os_sal.h"
#endif


/* IIC1 驱动(IO模拟) */

/**
 * IIC1_SCL : PB6
 * IIC1_SDA : PB7
 */

#define IIC1_SCL_PORT   GPIOB
#define IIC1_SCL_PIN    GPIO_PIN_6

#define IIC1_SDA_PORT   GPIOB
#define IIC1_SDA_PIN    GPIO_PIN_7

/* static var */


//IO方向设置
#define IIC_IO_SDA_DIR_IN()  {GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=0<<(7*2);}	//PB7输入模式
#define IIC_IO_SDA_DIR_OUT() {GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=1<<(7*2);} 	//PB7输出模式

//IO操作函数
#define IIC_IO_SDA_RD()		bsp_gpio_pin_get(IIC1_SDA_PORT, IIC1_SDA_PIN)

#define IIC_IO_SCL_SET()	bsp_gpio_pin_set(IIC1_SCL_PORT, IIC1_SCL_PIN)
#define IIC_IO_SCL_CLR()	bsp_gpio_pin_clr(IIC1_SCL_PORT, IIC1_SCL_PIN)

#define IIC_IO_SDA_SET()	bsp_gpio_pin_set(IIC1_SDA_PORT, IIC1_SDA_PIN)
#define IIC_IO_SDA_CLR()	bsp_gpio_pin_clr(IIC1_SDA_PORT, IIC1_SDA_PIN)


/* static var */
static uint8_t flag_init = 0;

#if (CONFIG_OS_ENABLE == 1)
static os_mutex_handle_t i2c1_mutex = NULL;
#endif


/* static func */

static __INLINE void i2c1_delay(void)
{
	delay_us(1);
}


/* export func */

/**
 * @brief 初始化
 * 
 */
void bsp_i2c1_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    if (flag_init) return ;

    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* IIC1_SCL : PB6 */
    GPIO_InitStruct.Pin = IIC1_SCL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(IIC1_SCL_PORT, &GPIO_InitStruct);

    /* IIC1_SDA : PB7 */
    GPIO_InitStruct.Pin = IIC1_SDA_PIN;
    HAL_GPIO_Init(IIC1_SDA_PORT, &GPIO_InitStruct);

    IIC_IO_SCL_SET();
    IIC_IO_SDA_SET();
    
#if (CONFIG_OS_ENABLE == 1)
    i2c1_mutex = os_mutex_create();
#endif

    flag_init = 1;
}

/**
 * @brief 产生IIC起始信号
 *
 */
void bsp_i2c1_start(void)
{
    IIC_IO_SDA_DIR_OUT(); // sda线输出
    IIC_IO_SDA_SET();
    IIC_IO_SCL_SET();
    i2c1_delay();
    IIC_IO_SDA_CLR(); // START:when CLK is high,DATA change form high to low
    i2c1_delay();
    IIC_IO_SCL_CLR(); //钳住I2C总线，准备发送或接收数据
}

/**
 * @brief 产生IIC停止信号
 *
 */
void bsp_i2c1_stop(void)
{
    IIC_IO_SDA_DIR_OUT(); // sda线输出
    IIC_IO_SCL_CLR();
    IIC_IO_SDA_CLR(); // STOP:when CLK is high DATA change form low to high
    i2c1_delay();
    IIC_IO_SCL_SET();
    i2c1_delay();
    IIC_IO_SDA_SET(); //发送I2C总线结束信号
}

/**
 * @brief 等待应答信号到来
 * 
 * @return uint8_t 0，接收应答成功;  1,接收应答失败;
 */
uint8_t bsp_i2c1_wait_ack(void)
{
    uint8_t ucErrTime = 0;
    IIC_IO_SDA_DIR_IN(); // SDA设置为输入
    IIC_IO_SDA_SET();
    i2c1_delay();
    IIC_IO_SCL_SET();
    i2c1_delay();
    while (IIC_IO_SDA_RD())
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            bsp_i2c1_stop();
            return 1;
        }
    }
    IIC_IO_SCL_CLR(); //时钟输出0
    return 0;
}

/**
 * @brief 产生ACK应答
 * 
 */
void bsp_i2c1_ack(void)
{
    IIC_IO_SCL_CLR();
    IIC_IO_SDA_DIR_OUT();
    IIC_IO_SDA_CLR();
    i2c1_delay();
    IIC_IO_SCL_SET();
    i2c1_delay();
    IIC_IO_SCL_CLR();
}

/**
 * @brief 不产生ACK应答
 * 
 */
void bsp_i2c1_noack(void)
{
    IIC_IO_SCL_CLR();
    IIC_IO_SDA_DIR_OUT();
    IIC_IO_SDA_SET();
    i2c1_delay();
    IIC_IO_SCL_SET();
    i2c1_delay();
    IIC_IO_SCL_CLR();
}

/**
 * @brief IIC发送一个字节
 * 
 * @param txd 从机有无应答: 1,有  0,无
 */
void bsp_i2c1_write_byte(uint8_t txd)
{
    uint8_t t, tmp;

    IIC_IO_SDA_DIR_OUT();
    IIC_IO_SCL_CLR(); //拉低时钟开始数据传输
    for (t = 0; t < 8; t++)
    {
        // IIC_IO_SDA = (txd & 0x80) >> 7;
        tmp = (txd & 0x80) >> 7;
        if (tmp) IIC_IO_SDA_SET();
        else IIC_IO_SDA_CLR();

        txd <<= 1;
        i2c1_delay(); //对TEA5767这三个延时都是必须的
        IIC_IO_SCL_SET();
        i2c1_delay();
        IIC_IO_SCL_CLR();
        i2c1_delay();
    }
}

/**
 * @brief 读1个字节
 * 
 * @return uint8_t 
 */
uint8_t bsp_i2c1_read_byte(void)
{
    unsigned char i, receive = 0;
    IIC_IO_SDA_DIR_IN(); // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        IIC_IO_SCL_CLR();
        i2c1_delay();
        IIC_IO_SCL_SET();
        receive <<= 1;
        if (IIC_IO_SDA_RD()) receive++;
        i2c1_delay();
    }
    return receive;
}

/**
 * @brief 读1个字节，发送nACK
 * 
 * @return uint8_t 
 */
uint8_t bsp_i2c1_read_byte_noack(void)
{
    unsigned char i, receive = 0;
    IIC_IO_SDA_DIR_IN(); // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        IIC_IO_SCL_CLR();
        i2c1_delay();
        IIC_IO_SCL_SET();
        receive <<= 1;
        if (IIC_IO_SDA_RD()) receive++;
        i2c1_delay();
    }
    bsp_i2c1_noack(); //发送nACK
    return receive;
}

/**
 * @brief 读1个字节，发送ACK
 * 
 * @return uint8_t 
 */
uint8_t bsp_i2c1_read_byte_ack(void)
{
    unsigned char i, receive = 0;
    IIC_IO_SDA_DIR_IN(); // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        IIC_IO_SCL_CLR();
        i2c1_delay();
        IIC_IO_SCL_SET();
        receive <<= 1;
        if (IIC_IO_SDA_RD()) receive++;
        i2c1_delay();
    }
    bsp_i2c1_ack(); //发送ACK
    return receive;
}


void bsp_i2c1_lock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_take(i2c1_mutex, OS_WAIT_MAX);
#endif
}

void bsp_i2c1_unlock(void)
{
#if (CONFIG_OS_ENABLE == 1)
    os_mutex_release(i2c1_mutex);
#endif
}

